﻿using UnityEngine;
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Reflection;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace LuaInterface {
    public class Util {
        private static List<string> luaPaths = new List<string>();

        public static int Int(object o) {
            return Convert.ToInt32(o);
        }

        public static float Float(object o) {
            return (float)Math.Round(Convert.ToSingle(o), 2);
        }

        public static long Long(object o) {
            return Convert.ToInt64(o);
        }

        public static int RandomInt(int min, int max) {
            return UnityEngine.Random.Range(min, max);
        }

        public static float Random(float min, float max) {
            return UnityEngine.Random.Range(min, max);
        }

        public static string Uid(string uid) {
            int position = uid.LastIndexOf('_');
            return uid.Remove(0, position + 1);
        }

        public static long GetTime() {
            TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks);
            return (long)ts.TotalMilliseconds;
        }

        /// <summary>
        /// 搜索子物体组件-GameObject版
        /// </summary>
        public static T Get<T>(GameObject go, string subnode) where T : Component {
            if (go != null) {
                Transform sub = go.transform.Find(subnode);
                if (sub != null) return sub.GetComponent<T>();
            }
            return null;
        }

        /// <summary>
        /// 搜索子物体组件-Transform版
        /// </summary>
        public static T Get<T>(Transform go, string subnode) where T : Component {
            if (go != null) {
                Transform sub = go.Find(subnode);
                if (sub != null) return sub.GetComponent<T>();
            }
            return null;
        }

        /// <summary>
        /// 搜索子物体组件-Component版
        /// </summary>
        public static T Get<T>(Component go, string subnode) where T : Component {
            return go.transform.Find(subnode).GetComponent<T>();
        }

        /// <summary>
        /// 添加组件
        /// </summary>
        public static T Add<T>(GameObject go) where T : Component {
            if (go != null) {
                T[] ts = go.GetComponents<T>();
                for (int i = 0; i < ts.Length; i++) {
                    if (ts[i] != null) GameObject.Destroy(ts[i]);
                }
                return go.gameObject.AddComponent<T>();
            }
            return null;
        }

        /// <summary>
        /// 添加组件
        /// </summary>
        public static T Add<T>(Transform go) where T : Component {
            return Add<T>(go.gameObject);
        }

        /// <summary>
        /// 查找子对象
        /// </summary>
        public static GameObject Child(GameObject go, string subnode) {
            return Child(go.transform, subnode);
        }

        /// <summary>
        /// 查找子对象
        /// </summary>
        public static GameObject Child(Transform go, string subnode) {
            Transform tran = go.Find(subnode);
            if (tran == null) return null;
            return tran.gameObject;
        }

        /// <summary>
        /// 取平级对象
        /// </summary>
        public static GameObject Peer(GameObject go, string subnode) {
            return Peer(go.transform, subnode);
        }

        /// <summary>
        /// 取平级对象
        /// </summary>
        public static GameObject Peer(Transform go, string subnode) {
            Transform tran = go.parent.Find(subnode);
            if (tran == null) return null;
            return tran.gameObject;
        }

        /// <summary>
        /// 计算字符串的MD5值
        /// </summary>
        public static string md5(string source) {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] data = System.Text.Encoding.UTF8.GetBytes(source);
            byte[] md5Data = md5.ComputeHash(data, 0, data.Length);
            md5.Clear();

            string destString = "";
            for (int i = 0; i < md5Data.Length; i++) {
                destString += System.Convert.ToString(md5Data[i], 16).PadLeft(2, '0');
            }
            destString = destString.PadLeft(32, '0');
            return destString;
        }

        /// <summary>
        /// 计算文件的MD5值
        /// </summary>
        public static string md5file(string file) {
            try {
                FileStream fs = new FileStream(file, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(fs);
                fs.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++) {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            } catch (Exception ex) {
                throw new Exception("md5file() fail, error:" + ex.Message);
            }
        }

        // public static bool HaveDirectory(string dir){
        //     return Directory.Exists(dir);
        // }
        // public static void DeleteDirectory(string dir,bool recursive){
        //     Directory.Delete(dir,recursive);
        // }
        // public static void DeleteFile(string path){
        //     File.Delete(path);
        // }

        /// <summary>
        /// 清除所有子节点
        /// </summary>
        public static void ClearChild(Transform go) {
            if (go == null) return;
            for (int i = go.childCount - 1; i >= 0; i--) {
                GameObject.Destroy(go.GetChild(i).gameObject);
            }
        }

        /// <summary>
        /// 清理内存
        /// </summary>
        public static void ClearMemory() {
            GC.Collect(); Resources.UnloadUnusedAssets();
            if (!LuaManager.IsInited) return;
            LuaManager mgr = LuaManager.Instance;
            if (mgr != null) mgr.LuaGC();
        }

        /// <summary>
        /// 取得数据存放目录
        /// </summary>
        public static string DataPath {
            get {
                if (Application.isMobilePlatform) {
                    return Application.persistentDataPath + "/" ;
                }
				return Application.streamingAssetsPath + "/";
            }
        }

        public static string GetRelativePath() {
            if (Application.isEditor)
                return "file://" + System.Environment.CurrentDirectory.Replace("\\", "/") + "/Assets/" + Application.streamingAssetsPath + "/";
			else if (Application.isMobilePlatform || Application.isConsolePlatform)
                return "file:///" + DataPath;
            else // For standalone player.
                return "file://" + Application.streamingAssetsPath + "/";
        }

        /// <summary>
        /// 取得行文本
        /// </summary>
        public static string GetFileText(string path) {
            return File.ReadAllText(path);
        }

		/// <summary>
		/// RenderTexture 转Texture
		/// </summary>
		/// <returns>The texture to texture2 d.</returns>
		/// <param name="rt">Rt.</param>
		public static Texture2D RenderTextureToTexture2D(RenderTexture rt , Rect rect){
			if(rt!=null){
				Texture2D t = new Texture2D((int)rect.width,(int)rect.height,TextureFormat.ARGB32,false);
				RenderTexture.active = rt;
				t.ReadPixels( rect,0,0,false);
				t.Apply();
				RenderTexture.active = null;
				return t;
			}
			return null;
		}

		/// <summary>
		/// 写二进制
		/// </summary>
		/// <param name="path">Path.</param>
		/// <param name="bytes">Bytes.</param>
		public static void WriteBytes(string path,byte[] bytes)
		{
			string dir = Path.GetDirectoryName(path);
			if(!Directory.Exists(dir)){
				Directory.CreateDirectory(dir);
			}
			File.WriteAllBytes(path,bytes);
		}

		/// <summary>
		/// 保存RenderTexture为png 到本地
		/// </summary>
		/// <param name="filePath">File path.</param>
		/// <param name="rt">Rt.</param>
		public static void SaveRenderTexture(string filePath,RenderTexture rt)
		{
			if(rt){
				Texture2D t = RenderTextureToTexture2D(rt,new Rect(0,0,rt.width,rt.height));
				byte[] bytes = t.EncodeToPNG();
				WriteBytes(filePath, bytes );
			}
		}
		/// <summary>
		/// 保存Texture2D为png 到本地
		/// </summary>
		/// <param name="filePath">File path.</param>
		/// <param name="t">T.</param>
		public static void SaveTexture2D(string filePath,Texture2D t)
		{
			if(t){
				byte[] bytes = t.EncodeToPNG();
				WriteBytes(filePath, bytes );
			}
		}

		/// <summary>
		/// 是否是Mobile平台
		/// </summary>
		/// <returns><c>true</c> if this instance is mobile; otherwise, <c>false</c>.</returns>
		public bool IsMobile(){
			return Application.isMobilePlatform;
		}
		/// <summary>
		/// 是否是Android 平台
		/// </summary>
		/// <returns><c>true</c> if this instance is android; otherwise, <c>false</c>.</returns>
		public bool IsAndroid(){
			return Application.platform == RuntimePlatform.Android;
		}
		/// <summary>
		/// 是否是ios 平台
		/// </summary>
		/// <returns><c>true</c> if this instance is IO; otherwise, <c>false</c>.</returns>
		public bool IsIOS(){
			return Application.platform == RuntimePlatform.IPhonePlayer;
		}
		/// <summary>
		/// 是否是Editor
		/// </summary>
		/// <returns><c>true</c> if this instance is editor; otherwise, <c>false</c>.</returns>
		public bool IsEditor(){
			return Application.isEditor;
		}

        /// <summary>
        /// 应用程序内容路径
        /// </summary>
        public static string AppContentPath() {
            string path = string.Empty;
            switch (Application.platform) {
                case RuntimePlatform.Android:
                    path = "jar:file://" + Application.dataPath + "!/assets/";
                break;
                case RuntimePlatform.IPhonePlayer:
                    path = Application.dataPath + "/Raw/";
                break;
                default:
                    path = Application.dataPath + "/" ;
                break;
            }
            return path;
        }

        public static void Log(string str) {
            Debug.Log(str);
        }

        public static void LogWarning(string str) {
            Debug.LogWarning(str);
        }

        public static void LogError(string str) {
            Debug.LogError(str);
        }

        /// <summary>
        /// 防止初学者不按步骤来操作
        /// </summary>
        /// <returns></returns>
        public static int CheckRuntimeFile() {
            if (!Application.isEditor) return 0;
            string streamDir = Application.dataPath + "/StreamingAssets/";
            if (!Directory.Exists(streamDir)) {
                return -1;
            } else {
                string[] files = Directory.GetFiles(streamDir);
                if (files.Length == 0) return -1;

                if (!File.Exists(streamDir + "files.txt")) {
                    return -1;
                }
            }
            string sourceDir = Application.dataPath + "/Framework/ToLua/Source/Generate/";
            if (!Directory.Exists(sourceDir)) {
                return -2;
            } else {
                string[] files = Directory.GetFiles(sourceDir);
                if (files.Length == 0) return -2;
            }
            return 0;
        }

        /// <summary>
        /// 执行Lua方法
        /// </summary>
        public static object[] CallMethod(string module, string func, params object[] args) {
            if (!LuaManager.IsInited) return null;
            LuaManager luaMgr = LuaManager.Instance;
            return luaMgr.CallFunction(module + "." + func, args);
        }

        /// <summary>
        /// 检查运行环境
        /// </summary>
        public static bool CheckEnvironment() {
#if UNITY_EDITOR
            int resultId = Util.CheckRuntimeFile();
            if (resultId == -1) {
                Debug.LogError("没有找到框架所需要的资源，单击Game菜单下Build xxx Resource生成！！");
                EditorApplication.isPlaying = false;
                return false;
            } else if (resultId == -2) {
                Debug.LogError("没有找到Wrap脚本缓存，单击Lua菜单下Gen Lua Wrap Files生成脚本！！");
                EditorApplication.isPlaying = false;
                return false;
            }
#endif
            return true;
        }

        public static void ClearAllEvents(object objectHasEvents){
            var events = objectHasEvents.GetType().GetEvents();
            if (events == null || events.Length < 1)
            {  
                return;
            } 
            foreach (var info in events)
            {
                ClearEvents(objectHasEvents,info.Name);
            }
        }

        public static void ClearEvents(object objectHasEvents, string eventName)
        {  
            if (objectHasEvents == null)
            {  
                return;
            }  
            Delegate[] invokeList = GetObjectEventList(objectHasEvents, eventName);
            if (invokeList != null)
            {
                Type t = objectHasEvents.GetType();
                foreach (Delegate del in invokeList)
                {
                    t.GetEvent(eventName).RemoveEventHandler(objectHasEvents, del);
                }
            }
        }

        private static Delegate[] GetObjectEventList(object p_Object, string p_EventName)
        {
			FieldInfo _Field = p_Object.GetType().GetField(p_EventName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
            if (_Field == null)
            {
                return null;
            }
            object _FieldValue = _Field.GetValue(p_Object);
            if (_FieldValue != null && _FieldValue is Delegate)
            {
                Delegate _ObjectDelegate = (Delegate)_FieldValue;
                return _ObjectDelegate.GetInvocationList();
            }

            return null;
        }


        /// <summary>
        /// 通过文件文件加载图片
        /// </summary>
        /// <returns>The texture2 d.</returns>
        /// <param name="relativePath">Relative path.</param>
        /// <param name="readOnly">If set to <c>true</c> read only.</param>
        public static Texture2D LoadTexture2D(string path,bool readOnly = true,TextureFormat format = TextureFormat.ARGB32){
            if(System.IO.File.Exists(path)){
                var data = System.IO.File.ReadAllBytes(path);
                Texture2D t = new Texture2D(2,2,format,false,true);
                t.LoadImage(data,readOnly);
                return t;
            }
            return null;
        }

        // public static Texture2D LoadImageData(byte[] data,bool readOnly = true,TextureFormat format = TextureFormat.ARGB32){
        //     if(data!=null){
        //         Texture2D t = new Texture2D(2,2,format,false,true);
        //         t.LoadImage(data,readOnly);
        //         return t;
        //     }
        //     return null;
        // }
    }
}